{ "cells": [ { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "# Production Mix\n", "## Problem definition\n", "Chappie Ltd. has 3 production lines (A, B, and C) to make 4 different types of metal sheets of width 0.4, 05, 0.6, and 0.7 mm. The company needs to meet the monthly demand for each kind of product (in Tons) expressed in the next table:\n", "\n", "| **Sheet 0.4 mm** | **Sheet 0.5 mm** | **Sheet 0.6 mm** | **Sheet 0.7 mm** |\n", "|------------------|------------------|------------------|------------------|\n", "| 500 | 1200 | 1500 | 300 |\n", "\n", "\n", "The production lines do not have the same overall efficiency for all types of sheets. Furthermore, due to design constraints, not all the lines are capable of manufacturing all types of sheets. The table below indicates the manufacturing costs in € of the different products in the different lines: a dash “-“ means that it is not possible to manufacture a product in a line:\n", "\n", "| Line | Sheet 0.4 mm | Sheet 0.5 mm | Sheet 0.6 mm | Sheet 0.7 mm |\n", "|---------|--------------|--------------|--------------|--------------|\n", "| A | 60 | 50 | 50 | 45 |\n", "| B | 80 | 70 | 75 | 70 |\n", "| C | - | 60 | 60 | - |\n", "\n", "The different lines have the following capacities (in hours) in the planning period:\n", "\n", "\n", "| A | B | C |\n", "|-----|-----|-----|\n", "| 500 | 480 | 370 |\n", "\n", "And the following table represents the manufacturing time (hours) per ton of product required for each type of metal sheet in the different lines:\n", "\n", "| Line | Sheet 0.4 mm | Sheet 0.5 mm | Sheet 0.6 mm | Sheet 0.7 mm |\n", "|------------|----------------------|----------------------|----------------------|----------------------|\n", "| A | 0.4 | 0.3 | 0.3 | 0.25 |\n", "| B | 0.8 | 0.6 | 0.7 | 0.6 |\n", "| C | - | 0.5 | 0.4 | - |" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": "**Formulate a linear programming problem to obtain the monthly production plan: quantity of metal sheet in tons of each type of metal sheet to be manufactured in each production line**" }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "**indexes**\n", "\n", "i: Manufacturing lines (A,B,C)\n", "\n", "j: Product types Sheet (0.4, 0.5, 0.6, 0.7) mm\n", "\n", "**Decision Variables**\n", "\n", "$x_{ij}$ = Quantity of product j to produce in line i\n", "\n", "**Objective function\n", "Minimize cost\n", "\n", "$\\min z = \\sum_i\\sum_j c_{ij}*x_{ij}$\n", "\n", "where $c_{ij}$ is the cost of manufacturing product j in line i as expressed in the second table.\n", "\n", "**Constraints**\n", "**Capacity**\n", "\n", "$\\sum_{j}a_{ij}·x_{ij} <= b_{i}, \\forall i$\n", "\n", "\n", "Where $a_{ij}$ represent the manufacturing time required to manufacture product j in line i as expressed in the last table and b_{i} represents the capacity of line i for the planning period\n", "\n", "\n", "**Demand**\n", "\n", "$\\sum_{i}{x_{ij}}>= d_{j}, \\forall j$\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "# Let's start importing the library PuLP to solve linear programs\n", "import pulp\n", "# We are going to use panda to display the results as tables using Panda\n", "import pandas as pd\n", "#And we will use numpy to perform array operations\n", "import numpy as np\n", "#We will use display and Markdown to format the output of code cells as Markdown\n", "from IPython.display import display, Markdown" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "# Create an instance of the problem class using LpProblem\n", "model = pulp.LpProblem(\"Chappie_example\", pulp.LpMinimize)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "\n", "# Define index i (lines)\n", "line_names = ('A', 'B', 'C')\n", "\n", "# Define index j (product types )\n", "product_types = ('4', '5', '6', '7')\n", "\n", "\n", "# Then we create a variable from a dictionary, using the variable names as keys\n", "variables = pulp.LpVariable.dicts(\"x\",\n", " [(i,j) for i in line_names for j in product_types],\n", " lowBound=0,\n", " cat='Continuous')\n", "\n", " \n", "# Define coefficients\n", "coefficients = [[60, 50, 50, 45], [80, 70, 75, 70], [0, 60, 60, 0]]\n", "\n", "\n", "# Define objective function\n", "\n", "model += (\n", " pulp.lpSum([\n", " coefficients[i][j] * variables[(line_names[i],product_types[j])]\n", " for i in range(len(line_names)) for j in range(len(product_types))])\n", "), \"Cost\"\n", "\n", "# Capacity Constraints\n", "capacity=[500, 480, 370]\n", "\n", "A = [[0.4, 0.3, 0.3, 0.25], [0.8, 0.6, 0.7, 0.6], [0, 0.5, 0.4, 0]]\n", "\n", "for i in range(len(line_names)): \n", " model += pulp.lpSum([\n", " A[i][j] * variables[(line_names[i],product_types[j])] \n", " for j in range(len(product_types))]) <= capacity[i] , line_names[i]\n", "\n", "# Demand constraints\n", "demand = [500, 1200, 1500, 300]\n", "\n", "for j in range(len(product_types)):\n", " model += pulp.lpSum([\n", " variables[(line_names[i],product_types[j])] \n", " for i in range(len(line_names))]) >= demand[j], product_types[j]" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/plain": [ "'Optimal'" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Solve our problem\n", "model.solve()\n", "pulp.LpStatus[model.status]" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "data": { "text/markdown": [ "The value of the objective function is **146416.67**" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/markdown": [ "The following tables show the values obtained: " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
VariablesSolutionReduced cost
(A, 4)x_('A',_'4')0.0000086.666667
(A, 5)x_('A',_'5')1091.666700.000000
(A, 6)x_('A',_'6')575.000000.000000
(A, 7)x_('A',_'7')0.0000061.666667
(B, 4)x_('B',_'4')0.0000080.000000
(B, 5)x_('B',_'5')108.333330.000000
(B, 6)x_('B',_'6')0.000005.000000
(B, 7)x_('B',_'7')0.0000070.000000
(C, 4)x_('C',_'4')500.000000.000000
(C, 5)x_('C',_'5')0.000002.500000
(C, 6)x_('C',_'6')925.000000.000000
(C, 7)x_('C',_'7')300.000000.000000
\n", "
" ], "text/plain": [ " Variables Solution Reduced cost\n", "(A, 4) x_('A',_'4') 0.00000 86.666667\n", "(A, 5) x_('A',_'5') 1091.66670 0.000000\n", "(A, 6) x_('A',_'6') 575.00000 0.000000\n", "(A, 7) x_('A',_'7') 0.00000 61.666667\n", "(B, 4) x_('B',_'4') 0.00000 80.000000\n", "(B, 5) x_('B',_'5') 108.33333 0.000000\n", "(B, 6) x_('B',_'6') 0.00000 5.000000\n", "(B, 7) x_('B',_'7') 0.00000 70.000000\n", "(C, 4) x_('C',_'4') 500.00000 0.000000\n", "(C, 5) x_('C',_'5') 0.00000 2.500000\n", "(C, 6) x_('C',_'6') 925.00000 0.000000\n", "(C, 7) x_('C',_'7') 300.00000 0.000000" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ConstraintRight Hand SideSlackShadow Price
0A500.00-0.00-66.67
1B480.00415.000.00
2C370.00-0.00-25.00
34500.00-0.000.00
451200.00-0.0070.00
561500.00-0.0070.00
67300.00-0.000.00
\n", "
" ], "text/plain": [ " Constraint Right Hand Side Slack Shadow Price\n", "0 A 500.00 -0.00 -66.67\n", "1 B 480.00 415.00 0.00\n", "2 C 370.00 -0.00 -25.00\n", "3 4 500.00 -0.00 0.00\n", "4 5 1200.00 -0.00 70.00\n", "5 6 1500.00 -0.00 70.00\n", "6 7 300.00 -0.00 0.00" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Solution\n", "max_z = pulp.value(model.objective)\n", "\n", "#We use display and Markdown to show the value using markdown\n", "display(Markdown(\"The value of the objective function is **%.2f**\"%max_z))\n", "\n", "\n", "# Print our decision variable values\n", "display(Markdown(\"The following tables show the values obtained: \"))\n", "# First we create a dataframe from the dictionary of the solution. We want to use the variable indexes to present the results and \n", "# place the different values provided by the solver in the data frame.\n", "var_df = pd.DataFrame.from_dict(variables, orient=\"index\", \n", " columns = [\"Variables\"], dtype=object)\n", "# First we add the solution. We apply a lambda function to get only two decimals:\n", "var_df[\"Solution\"] = var_df[\"Variables\"].apply(lambda item: item.varValue)\n", "# We do the same for the reduced cost:\n", "var_df[\"Reduced cost\"] = var_df[\"Variables\"].apply(lambda item: item.dj)\n", "\n", "\n", "# We use the display function to represent the results:\n", "display(var_df)\n", "\n", "\n", "# we define a dictionary with the constraints:\n", "const_dict = dict(model.constraints)\n", "#We create a list of records from the dictionary and exclude the Expression to have a more compact solution. \n", "con_df = pd.DataFrame.from_records(list(const_dict.items()), exclude=[\"Expression\"], columns=[\"Constraint\", \"Expression\"])\n", "\n", "#Now we add columns for the solution, the slack and shadow price\n", "\n", "con_df[\"Right Hand Side\"] = con_df[\"Constraint\"].apply(lambda item: \"{:.2f}\".format(-const_dict[item].constant))\n", "con_df[\"Slack\"] = con_df[\"Constraint\"].apply(lambda item: \"{:.2f}\".format(const_dict[item].slack))\n", "con_df[\"Shadow Price\"] = con_df[\"Constraint\"].apply(lambda item: \"{:.2f}\".format(const_dict[item].pi))\n", "\n", "# And we display the results\n", "display(con_df)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" }, "pycharm": { "stem_cell": { "cell_type": "raw", "source": [], "metadata": { "collapsed": false } } } }, "nbformat": 4, "nbformat_minor": 2 }